package com.hyfrogx.modules.app.controller;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.http.HttpRequest;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.hyfrogx.common.annotation.SysLog;
import com.hyfrogx.common.log.LogEnum;
import com.hyfrogx.common.log.LogUtils;
import com.hyfrogx.common.param.Constants;
import com.hyfrogx.common.qcloud.UploadUtils;
import com.hyfrogx.common.utils.Constant;
import com.hyfrogx.common.utils.MD5Utils;
import com.hyfrogx.common.utils.R;
import com.hyfrogx.common.utils.RedisUtils;
import com.hyfrogx.common.validator.ValidatorUtils;
import com.hyfrogx.modules.app.annotation.Login;
import com.hyfrogx.modules.app.entity.Sms;
import com.hyfrogx.modules.app.entity.User;
import com.hyfrogx.modules.app.form.ChangePwdForm;
import com.hyfrogx.modules.app.form.ClientUserForm;
import com.hyfrogx.modules.app.form.CodeLoginForm;
import com.hyfrogx.modules.app.form.sendYzmVO;
import com.hyfrogx.modules.app.service.SmsService;
import com.hyfrogx.modules.app.service.UserService;
import com.hyfrogx.modules.app.utils.FrogConstant;
import com.hyfrogx.modules.app.utils.JwtUtils;
import com.hyfrogx.modules.app.utils.StringUtils;
import com.hyfrogx.modules.operation.service.umeng.UmengService;
import com.hyfrogx.modules.user.entity.HyUserBean;
import com.hyfrogx.modules.user.service.HyUserBeanService;
import com.hyfrogx.modules.zoom.entity.HyLoginInfo;
import com.hyfrogx.modules.zoom.form.CreateLoginInfoForm;
import com.hyfrogx.modules.zoom.form.UserInfoForm;
import com.hyfrogx.modules.zoom.service.HyLoginInfoService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import redis.clients.jedis.Jedis;
import springfox.documentation.annotations.ApiIgnore;

import javax.annotation.PostConstruct;
import java.util.*;

/**
 * @author ：Li9527
 * @date ：Created in 2019-09-16 10:43
 * @description：移动端登录注册接口
 * @modified By：
 * @version: 1.0.0
 */
@RestController
@RequestMapping("/api/login")
@Api(value = "ApiLoginController", tags = {"客户端--用户登录注册"})
public class ApiLoginController {

    // 创建对象
    private Map<Object, Object> yzmCache;

    @Autowired
    RedisUtils redisUtils;

    @Autowired
    UserService userService;

    @Autowired
    HyLoginInfoService hyLoginInfoService;

    @Autowired
    SmsService smsService;

    @Autowired
    private JwtUtils jwtUtils;

    @Autowired
    UmengService umengService;

    @Autowired
    HyUserBeanService userBeanService;

    @PostConstruct
    private Map<Object, Object> getCacheManage() {
        if (null == yzmCache) {
            yzmCache = redisUtils.getMap(FrogConstant.RedisKey.REGISTER_YZM);
        }
        return yzmCache;
    }

    Logger LOGIN_LOG = LogUtils.Logger(LogEnum.LOGIN_LOGS);

    /**
     * 发送短信验证码
     *
     * @param sendYzmVO
     * @return
     */
    @ApiOperation("发送短信验证码 🐉")
    @PostMapping("sendYzm")
    public R sendYzm(@RequestBody sendYzmVO sendYzmVO) {
        // 如果是没注册过忘记密码
        if (sendYzmVO.getType() == 2) {
            User user = userService.getOne(new QueryWrapper<User>().eq("phone", sendYzmVO.getPhone()));
            if (ObjectUtil.isNull(user)) {
                return R.error("您尚未注册");
            }
        }
        // 先去redis 查询是否 60S内已经发送
        String phone = sendYzmVO.getPhone();
        Object tempCode = redisUtils.get(FrogConstant.DEFAULT_CODE_KEY + phone);
        if (tempCode != null) {
            return R.ok("验证码未失效，请失效后再次申请");
        }

        // 获取6位验证码
        String code = RandomUtil.randomNumbers(6);

        // 保存进redis 过期时间120秒
        redisUtils.set(FrogConstant.DEFAULT_CODE_KEY + phone, code, FrogConstant.SMS_CODE_EXPIRE);

        // 发送短信 测试可用先注释,通过redis查看
        ArrayList<String> params = new ArrayList<>();
        params.add(code);
        params.add("2");
        boolean issuccess = smsService.sendSms(phone, FrogConstant.SMS_TMP_YZM, params);
        if (issuccess) {
            // 持久化
            Sms o = new Sms();
            o.setPhone(phone);
            o.setStatus(1);
            o.setDate(new Date());
            o.setContent("手机号：" + phone + ";短信模板：" + FrogConstant.SMS_TMP_YZM + ";验证码：" + code);
            smsService.createSms(o);
            return R.ok();
        }
        // 发送失败删除redis
        redisUtils.delete(FrogConstant.DEFAULT_CODE_KEY + phone);

        return R.error("验证码发送失败!");
    }


    /**
     * 登录
     */
    @PostMapping("")
    @ApiOperation("登录 🐉")
    public R login(@RequestBody ClientUserForm form) {
        LOGIN_LOG.info("登录接口");
        //表单校验
        ValidatorUtils.validateClientEntity(form);
        //用户登录
        User user = userService.login(form);
        //生成jwt token
        String token = jwtUtils.generateToken(user.getUid(), user.getPhone());
        LOGIN_LOG.info("用户登录phone:" + user.getPhone());
        // 获取余额
        user.setMoney(userService.getMoneyByUid(user.getUid()));
        Map<String, Object> map = new HashMap<>();
        map.put("token", token);
        map.put("expire", jwtUtils.getExpire());
        // 插入用户余额
        user.setPassword(null);
        user.setMoney(userService.getMoneyByUid(user.getUid()));
        map.put("user", user);
        // 先检索前面有没有device_token,有的话先删除再创建
        Object old_device_token = redisUtils.getMap(FrogConstant.RedisKey.DEVICE_TOKEN).get(user.getUid().toString());
        LOGIN_LOG.info("old_device_token:" + old_device_token);
        if (old_device_token != null) {
            redisUtils.removeFromMap(FrogConstant.RedisKey.DEVICE_TOKEN, user.getUid().toString());
            LOGIN_LOG.info("移除旧的设备token");
        }
        String user_device_token = form.getDeviceToken();
        LOGIN_LOG.info("user_device_token" + user_device_token);
        umengService.addDeviceToken(Convert.toInt(user.getUid()), user_device_token);

        LOGIN_LOG.info("返回值: " + JSONObject.toJSONString(map));

        return R.ok(map);
    }

    /**
     * 手机号+验证码登录,如果用户不存在,就创建新用户
     *
     * @param form
     * @return
     */
    @PostMapping("codeLogin")
    @ApiOperation("手机号+验证码登录 🐉")
    public R codeLogin(@RequestBody CodeLoginForm form) {
        //表单校验
        ValidatorUtils.validateClientEntity(form);
        String phone = form.getPhone();
        String code = form.getCode();
        Object tempCode = redisUtils.get(FrogConstant.DEFAULT_CODE_KEY + phone);
        if (tempCode == null) {
            return R.error("验证码已过期,请重新获取!");
        }
        if (tempCode.equals(code)) {
            Map<String, Object> map = new HashMap<>();
            User user = userService.getOne(new QueryWrapper<User>().eq("phone", phone));
            Long uid;
            // 如果用户不存在就创建一个用户,密码默认
            if (user == null) {
                // 是否初次注册标记 1是0否
                map.put("firstRegiset", 1);
                User frogUser = new User();
                frogUser.setPhone(phone);
                frogUser.setPassword(MD5Utils.MD5Encode(Constant.DEFAULT_PWD + phone.substring(0, 5)));
                frogUser.setStatus(Constant.BasicStatus.TRUE.getValue());
                frogUser.setCreated(new Date());
                frogUser.setUsername(phone);
                frogUser.setAccount(phone);
                frogUser.setHead("123456789default.png");
                // 生成飞鸽号
                userService.register(frogUser);
                user = userService.getOne(new QueryWrapper<User>().eq("phone", phone));
                if (form.getDeviceToken() != null) {
                    // 删除用户的deviceToken
                    Object old_device_token = redisUtils.getMap(FrogConstant.RedisKey.DEVICE_TOKEN).get(user.getUid().toString());
                    if (old_device_token != null) {
                        redisUtils.removeFromMap(FrogConstant.RedisKey.DEVICE_TOKEN, user.getUid().toString());
                    }
                    umengService.addDeviceToken(Convert.toInt(user.getUid()), form.getDeviceToken());
                } else {
                    return R.error("DeviceToken必传");
                }
            } else {
                map.put("firstRegiset", 0);
                uid = user.getUid();
                // 修改最后登录时间
                user.setUpdateTime(new Date());
                userService.updateById(user);
                if (form.getDeviceToken() != null) {
                    // 删除用户的deviceToken
                    Object old_device_token = redisUtils.getMap(FrogConstant.RedisKey.DEVICE_TOKEN).get(user.getUid().toString());
                    if (old_device_token != null) {
                        redisUtils.removeFromMap(FrogConstant.RedisKey.DEVICE_TOKEN, user.getUid().toString());
                    }
                    umengService.addDeviceToken(Convert.toInt(user.getUid()), form.getDeviceToken());
                } else {
                    return R.error("DeviceToken必传");
                }
            }
            //生成jwt token
            String token = jwtUtils.generateToken(user.getUid(), phone);
            map.put("token", token);
            map.put("expire", jwtUtils.getExpire());
            // 插入用户余额
            user.setPassword(null);
            user.setMoney(userService.getMoneyByUid(user.getUid()));
            map.put("user", user);
            return R.ok(map);
        }
        return R.error("验证码不准确,请重新获取!");
    }

    /**
     * 注册
     *
     * @param phone 手机号
     * @param yzm   验证码
     * @param psw   密码
     * @return R
     */
    @PostMapping("register")
    @ApiOperation("注册 🐉")
    public R register(String phone, String yzm, String psw) {
        if (phone == null) {
            return R.error("手机号必传");
        }
        if (yzm == null) {
            return R.error("验证码必传");
        }
        if (psw == null) {
            return R.error("密码必传");
        }
        // 校验验证码
        // 先去redis 查询是否 60S内已经发送
        Object tempCode = redisUtils.get(FrogConstant.DEFAULT_CODE_KEY + phone);
        if (tempCode == null) {
            return R.error("验证码已失效");
        }
        if (!redisUtils.get(FrogConstant.DEFAULT_CODE_KEY + phone).equals(yzm)) {
            return R.error("验证码不正确");
        } else {
            User user = new User();
            user.setPhone(phone);
            user.setPassword(MD5Utils.MD5Encode(psw + phone.substring(0, 5)));
            user.setStatus(Constant.BasicStatus.TRUE.getValue());
            user.setCreated(new Date());
            user.setUsername(phone);
            user.setAccount(phone);
            user.setHead("123456789default.png");
            //用以日志记录
            userService.register(user);
        }
        return R.ok();
    }

    /**
     * 用户重置密码
     *
     * @param uid
     * @param form
     * @return
     */
    @Login
    @PostMapping("changePassword")
    @ApiOperation("用户重置密码 🐉")
    public R changePassword(@ApiIgnore @RequestAttribute(value = "userId") Long uid,
                            @RequestBody ChangePwdForm form) {

        User user = userService.getOne(new QueryWrapper<User>().eq("uid", uid));
        if (user == null) {
            return R.error("用户不存在");
        }
        if (StringUtils.isNotBlank(form.getPassword())) {
            String npwd = MD5Utils.MD5Encode(form.getPassword() + user.getPhone().substring(0, 5));
            user.setPassword(npwd);
            userService.updateById(user);
        }
        return R.ok();
    }

    /**
     * 创建用户登录信息记录
     *
     * @throws Exception
     */
    @Login
    @PostMapping("/loginInfo/create")
    @ApiOperation("创建用户登录信息记录 🐉")
    public R create(@RequestBody @Validated CreateLoginInfoForm form,
                    @ApiIgnore @RequestAttribute(value = "userId") Long uid) throws Exception {
        // 检查该用户该设备是否登陆过
        HyLoginInfo juHyLoginInfo = hyLoginInfoService.getOne(new QueryWrapper<HyLoginInfo>().eq(
                "uid", uid).eq("division_code", form.getDivisionCode()));
        if (juHyLoginInfo != null) {
            // 只更新最后登录时间
            juHyLoginInfo.setLastLoginTime(new Date());
            hyLoginInfoService.updateById(juHyLoginInfo);
            return R.ok("记录成功");
        } else {
            User user = userService.getById(uid);
            HyLoginInfo hyLoginInfo = new HyLoginInfo();
            hyLoginInfo.setCratetime(new Date());
            hyLoginInfo.setLastLoginTime(new Date());
            BeanUtil.copyProperties(form, hyLoginInfo);
            hyLoginInfo.setUid(uid);
            hyLoginInfo.setPhone(user.getPhone());
            hyLoginInfo.setStatus(Constants.Status.TRUE);
            Boolean b = hyLoginInfoService.save(hyLoginInfo);
            if (b) {
                return R.ok("记录成功");
            } else {
                return R.error("记录失败");
            }
        }


    }

    @Login
    @PostMapping("logout")
    @ApiOperation("客户端用户退出 🐉")
    public R logout(@ApiIgnore @RequestAttribute(value = "userId") Long userId) {
        //todo 无处理逻辑，仅用以记录日志
        // 删除用户的deviceToken
        LOGIN_LOG.info("客户端用户退出");
        Object old_device_token = redisUtils.getMap(FrogConstant.RedisKey.DEVICE_TOKEN).get(userId.toString());
        if (old_device_token != null) {
            redisUtils.removeFromMap(FrogConstant.RedisKey.DEVICE_TOKEN, userId.toString());
            LOGIN_LOG.info("删除old_device_token：" + old_device_token + ",uid:" + userId.toString());
        }
        return R.ok();
    }

    @Login
    @PostMapping("refreshDeviceToken")
    @ApiOperation("客户端进程重新激活刷新device_token 🐉")
    public R refresh(@ApiIgnore @RequestAttribute(value = "userId") Long userId,
                     @RequestParam(value = "user_device_token", required = true) String user_device_token) {
        // 删除上台设备该用户device_token
        Object old_device_token = redisUtils.getMap(FrogConstant.RedisKey.DEVICE_TOKEN).get(userId.toString());
        if (old_device_token != null) {
            redisUtils.removeFromMap(FrogConstant.RedisKey.DEVICE_TOKEN, userId.toString());
        }
        umengService.addDeviceToken(Convert.toInt(userId), user_device_token);
        return R.ok();
    }

    /**
     * 移动redis中的数据
     */
    @PostMapping("doingBean")
    @SuppressWarnings("resource")
//    @ApiOperation("移动redis中的数据")
    public R doingBean(HttpRequest request) {
        try {
            //遍历用户
            List<User> list = userService.list();
            //从redis中获取蛙豆
            Jedis jedis = new Jedis("118.89.248.233", 11207);
            jedis.auth("heyoovr@pwd123");
            String redisKey = "money:\"money\"";
            Map<String, String> map = jedis.hgetAll(redisKey);
            for (int i = 0; i < list.size(); i++) {
                String bean = map.get(list.get(i).getUid().toString());
                if (bean != null) {
                    HyUserBean userBean = new HyUserBean();
                    userBean.setMoney(Integer.valueOf(bean));
                    userBean.setUid(list.get(i).getUid());
                    userBeanService.save(userBean);
                }
            }
        } catch (Exception e) {
            R.error(e.getMessage());
        }
        return R.ok("成功");
    }


    /**
     * 上传用户头像
     *
     * @param file
     * @return
     */
    @Login
    @PostMapping("upload/accountimg")
//    @ApiOperation("上传用户头像")
    public R updateImg(@ApiIgnore @RequestAttribute(value = "userId") Long userId,
                       @RequestParam("file") MultipartFile file) {
        try {
            if (file == null) {
                return R.error("请选择上传图片!");
            }
            String path = userService.updateUserImg(file);
            User user = userService.getById(userId);
            user.setHead(path);
            userService.updateById(user);
            return R.ok(path);
        } catch (Exception e) {
            return R.error(e.getMessage());
        }
    }

    /**
     * 上传用户头像
     *
     * @return
     */
    @Login
    @PostMapping("uploadImg")
    @ApiOperation("用户头像上传 🐉")
    public R uploadImg(@RequestParam("file") MultipartFile file) {
        String result = null;
        if (file != null) {
            String fileName = UUID.randomUUID().toString() + file.getOriginalFilename()
                    .substring(file.getOriginalFilename()
                            .lastIndexOf("."), file.getOriginalFilename().length());
            result = UploadUtils.upload(UploadUtils.convertFile(file), fileName, FrogConstant.Path.USER);
        }
        return R.ok(result);
    }


    /**
     * 修改个人信息
     *
     * @param form
     * @return
     */
    @Login
    @ApiOperation("修改个人信息 🐉")
    @PostMapping("/updateUserInfo")
    public R updateUserInfo(@ApiIgnore @RequestAttribute(value = "userId") Long userId,
            @ApiParam(value = "修改信息请求表单", required = true) @RequestBody UserInfoForm form) {
        ValidatorUtils.validateEntity(form);
        User user = userService.getById(userId);
        if (user == null) {
            return R.error("用户uid错误");
        } else {
            user.setUsername(form.getUsername());
            if (form.getSex() != null) {
                user.setSex(form.getSex());
            }
            if (form.getSignature() != null) {
                user.setSignature(form.getSignature());
            }
            if (form.getHead() != null) {
                user.setHead(form.getHead());
            }
            if (form.getBirthday() != null) {
                user.setBirthday(form.getBirthday());
            }
            if (form.getEmail() != null) {
                user.setEmail(form.getEmail());
            }
            userService.updateById(user);
        }
        return R.ok();
    }

    /**
     * 刷新余额
     *
     * @return
     */
    @Login
    @PostMapping("refreshMoney")
    @ApiOperation("刷新余额 🐉")
    public R uploadImg(@ApiIgnore @RequestAttribute(value = "userId") Long userId) {
        Integer money = userService.getMoneyByUid(userId);
        return R.ok().put("data",money);
    }


    /**
     * 获取用户详情
     *
     * @param userId
     * @return
     */
    @Login
    @PostMapping("/info")
    @ApiOperation("获取用户详情 🐉")
    public R findUserinfoByUserId(@ApiIgnore @RequestAttribute Long userId) {
        User user = userService.getById(userId);
        // 插入用户余额
        user.setPassword(null);
        user.setMoney(userService.getMoneyByUid(user.getUid()));
        return R.ok().put("user", user);
    }

}
